/**
 * 记载图片
 * @param url 图片路径
 * @returns 图片
 */
export async function loadImage (url: string): Promise<HTMLImageElement | undefined> {
  return await new Promise((resolve) => {
    const image = new Image()
    image.crossOrigin = 'anonymous'
    image.src = url
    image.onload = () => {
      resolve(image)
    }
    image.onerror = () => {
      resolve(undefined)
    }
  })
}

export function getValue<T> (cache: any, key: string, dft: () => T): T {
  if (cache[key] === undefined) {
    cache[key] = dft()
  }
  return cache[key]
}

export function setValue<T> (cache: any, key: string, val: T, chg: (v: T) => void) {
  if (cache[key] !== val) {
    cache[key] = val
    chg(val)
  }
}

/**
 * 数字转颜色
 * @param val 数字
 * @returns 颜色例：'#000000'
 */
export function numberToColor (val: number) {
  return (0x1000000 + val).toString(16).replace('1', '#')
}

/**
 * 数字转浮点型字符串
 * @param val
 * @returns
 */
export function toFloatString (val: number) {
  return Number.isInteger(val) ? val.toFixed(1) : val.toString()
}

export class OneDimensional {
  k: number
  b: number
  /** 一维数据映射器 */
  constructor (from: [number, number], to: [number, number] = [0, 1]) {
    const d = from[1] - from[0]
    this.k = (to[1] - to[0]) / d
    this.b = (to[0] * from[1] - to[1] * from[0]) / d
  }

  /** 从from映射到to */
  forward (x: number) {
    return this.k * x + this.b
  }

  /** 从to映射到from */
  backward (y: number) {
    return (y - this.b) / this.k
  }
}

export function downloadCanvas (canvas: HTMLCanvasElement) {
  const a = document.createElement('a')
  a.href = canvas.toDataURL()
  a.download = 'canvas.png'
  a.click()
}

/**
 * 为目标函数添加防抖
 * @param func 目标函数
 * @param time 防抖时间间隔
 * @param immediately 是否立刻执行
 * @returns 防抖的目标函数
 */
export function antiShake<T extends (...args: any) => void> (func: T, time = 0, immediately = false): T {
  let handler = 0
  let lock = 0
  if (immediately) {
    return function (...args: any) {
      const now = Date.now()
      if (handler) {
        clearTimeout(handler)
      }
      if (lock < now) {
        func(...args)
        lock = now + time
      } else {
        handler = setTimeout(() => {
          handler = 0
          func(...args)
        }, time)
      }
    } as T
  } else {
    return function (...args: any) {
      if (handler) {
        clearTimeout(handler)
      }
      handler = setTimeout(() => {
        handler = 0
        func(...args)
      }, time)
    } as T
  }
}
